package mop.model.task.state;
import java.util.HashMap;
import java.util.Map;

import mop.model.task.*;
/**
 * State pattern
 * @author 	MOP Team 7
 */
public abstract class State implements StateInterface
{	
	/**
	 * Constructor
	 * @param t	Task for this state
	 * @post	Task is set to given task
	 * 	|this.task == t
	 */
	public State(Task t)
	{
		this.task = t;
	}
	
	/**
	 * Constructor when the creation of a state has been forced ignoring exceptions
	 * @param t Task for this state
	 * @param forced boolean that tells us wether it's a forced construction
	 */
	public State(Task t, boolean forced)
	{
		this.task = t;
		this.forced = forced;
	}
	
	/**
	 * CopyConstructor
	 */
	public State(State old)
	{
		this.forced = old.forced;
		this.task = old.task;
	}
	
	/***************************************************************************
	 * 						Status
	 ***************************************************************************/
	
	/**
	 * Use Case functionality
	 * Update details of task according to this state
     * @return returns false when details should not be updated
	 */
	public abstract boolean updateDetails();
	
	
	/**
	 * Refresh the status to comply with a correct 
	 * Unfinished -> Available/Unavailable
	 * Available/Unavailable -> (Available/Unavailable)
	 * SuccesFull -> Failed
	 */
	public abstract State refreshStatus();
	
	/**
	 * check on Business Rule nr 2
	 * this is the default clause valid for available and successful
	 * others reimplement this method
	 * @return the task that is not ok with the businessrule
	 */
	public TaskInterface rule2isMet()
	{
		for(TaskInterface t : this.getTask().getDependencyList())
		{
			if(t.getStatus().equals(Failed.stateName()) || t.getStatus().equals(Unfinished.stateName()))
			{
				return t;
			}
		}
		return null;
	}
	
	/**
	 * check on Business rule nr 3
	 * @return true if valid
	 */
	public abstract boolean rule3isMet();
	
	/**
	 * Return problem cases when setting a state to Failed or Unfinished
	 * @return a map with all problematic parents
	 */
	protected Map<String,String> rule2Parents()
	{
		Map<String,String> ret = new HashMap<String,String>();
		
		Task current = this.getTask();
		
		/** refresh all **/
		for(TaskInterface t : current.getAllParentList())
		{
			t.getStatus();
		}
		
		TaskMemento old = current.saveMemento();
		
		/** TODO this is dangerous */
		current.forceStatus(toString());
		
		/** now force a getStatus without refresh **/
		for(Task t : current.getAllParents())
		{
			if(t.forceGetStatus().rule2isMet() != null)
			{
				State newstate = t.forceGetStatus().refreshStatus();
				ret.put(t.getId(),newstate.toString());
			}
		}
		
		current.restoreMemento(old);
		
		if(ret.isEmpty())
			return null;
		
		return ret;
	}
	
	
	/***************************************************************************
	 * 						Task
	 ***************************************************************************/
	
	/**
	 * Inspector for task
	 * @return this.task
	 */
	public Task getTask()
	{
		return this.task;
	}
		
	/**
	 * Task for this state
	 */
	private final Task task;
	
	
	/***************************************************************************
	 * 						forced
	 ***************************************************************************/
	
	/**
	 * Inspector for forced
	 * @return this.forced
	 */
	public boolean getForced()
	{
		return this.forced;
	}
	
	/**
	 * Sometimes we need to ignore all exceptions and busnissrules and just
	 * build the damn state
	 * When this is the case forced = true;
	 */
	private boolean forced = false;
	
	/***************************************************************************
	 * 						Java object interface
	 ***************************************************************************/
	
	/**
	 * Compare state with string for ease of use
	 * this is only replaced by the one in Unfinished because
	 * Unfinished == Unfinished || Available || Unavailable
	 * 
	 * @param state
	 * 		the state name to compare with
	 * 
	 * @return this.getName.equals(state)
	 */
	public boolean equals(String state)
	{
		return (this.getName().equals(state));
	}
	
	/**
	 * Implement Interface to GUI
	 * @return stateName()
	 */
	public String getName()
	{
		return toString();
	}
	
	/**
	 * @see 	Object#toString()
	 */
	public String toString()
	{
		return "State";
	}

	/**
	 * return a string of the class name
	 * @return "State"
	 */
	public static String stateName()
	{
		return "State";
	}
	
	
}
